package com.pl.data.core.utils;

import cn.hutool.core.util.ReflectUtil;
import com.pl.data.core.interfaces.IFieldFunction;

import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.regex.Pattern;

/**
 * @ClasssName FunctionUtil
 * @Description 函数工具类
 * @Author Liuyh
 * @Date 2021/9/17
 * @Version V0.0.1
 */
public class FunctionUtil {

    private static final Pattern GET_PATTERN = Pattern.compile("get[A-Z].*");
    private static final Pattern IS_PATTERN = Pattern.compile("is[A-Z].*");

    /**
     * 获取字段名称
     *
     * @param fn
     * @param <T>
     * @return
     */
    public static <T> String getFieldName(IFieldFunction<T> fn) {
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            SerializedLambda invoke = (SerializedLambda) method.invoke(fn);
            // 得到方法名
            String getter = invoke.getImplMethodName();
            // 切割得到字段名
            if (GET_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(3);
            }
            if (IS_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(2);
            }
            return Introspector.decapitalize(getter);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException();
        }
    }


    /**
     * 获取字段名称
     *
     * @param fn
     * @param <T>
     * @return
     */
    public static <T, V> V getFieldValue(T obj, IFieldFunction<T> fn) {
        String name = getFieldName(fn);
        Object o = ReflectUtil.getFieldValue(obj, name);
        if (o == null) {
            return null;
        }
        V v = (V) o;
        return v;
    }



    /**
     * 获取方法名
     *
     * @param fn
     * @param <T>
     * @return
     */
    public static <T> String getMethodName(IFieldFunction<T> fn) {
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            SerializedLambda invoke = (SerializedLambda) method.invoke(fn);
            // 得到方法名
            return invoke.getImplMethodName();
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException();
        }
    }


}
